package com.storydo.thread.pool;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Application {

	public static void main(String[] args) {
		try {
			Argument argument = Argument.parse(args);
			log.info("thread count {}, param n {}, program {}", argument.getThreadCount(), argument.getNMax(),
					argument.getProgram());
			LocalDateTime expire = LocalDateTime.now().plus(argument.getTimeout());
			log.info("expire date {}", expire);
			
			AtomicLong paramNum = new AtomicLong(argument.getStart());
			LinkedBlockingQueue<TaskResult> resultQueue = new LinkedBlockingQueue<>();
			
			List<Task> taskList = new ArrayList<Task>();
			for (int i = 0; i < argument.getThreadCount(); i++) {
				Task task = new Task(String.format("%d", i), argument, paramNum);
				task.setResultQueue(resultQueue);
				taskList.add(task);
				task.start();
			}
			ArrayList<TaskResult> resultList = new ArrayList<TaskResult>();
			while(true) {
				TaskResult tr = resultQueue.poll(1, TimeUnit.MINUTES);
				if (tr != null) {
					resultList.add(tr);
					resultQueue.drainTo(resultList);
				}
				log.info("progress--> {}/{}", resultList.size(), argument.getNMax());
				if (resultList.size() >= argument.getNMax() || LocalDateTime.now().compareTo(expire) > 0) {
					break;
				}
			}
			boolean error = false;
			if (resultList.size() < argument.getNMax()) {
				log.error("------ 未能获取全部运算结果 ------");
				log.info("result json --->");
				log.info(JSON.toJSONString(resultList));
				log.info("<--- result json");
				error = true;
			}
			try (BufferedWriter bw = new BufferedWriter(new FileWriter(new File(argument.getOutput())))) {
				if (error) {
					// 覆盖输出
					bw.write("");
				} else {					
					if (argument.getNeedSum()) {
						bw.write(String.format("%f", 
								resultList.stream().mapToDouble(r -> Double.valueOf(r.getResult())).sum()));
					} else {
						bw.write(JSON.toJSONString(resultList));
					}
				}
			}
			log.debug("active thread {} .", taskList.stream().filter(t -> t.isAlive()).count());
			//准备停止进程
			for (Task task : taskList) {
				task.kill();
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

}
